package com.yonyou.crm.bpub.approval.service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import yonyou.bpm.rest.BpmRest;
import yonyou.bpm.rest.BpmRests;
import yonyou.bpm.rest.HistoryService;
import yonyou.bpm.rest.RuntimeService;
import yonyou.bpm.rest.TaskService;
import yonyou.bpm.rest.exception.RestException;
import yonyou.bpm.rest.param.BaseParam;
import yonyou.bpm.rest.request.RestVariable;
import yonyou.bpm.rest.request.RestVariable.RestVariableScope;
import yonyou.bpm.rest.request.historic.BpmHistoricProcessInstanceParam;
import yonyou.bpm.rest.request.historic.HistoricProcessInstancesQueryParam;
import yonyou.bpm.rest.request.historic.HistoricTaskQueryParam;
import yonyou.bpm.rest.request.identity.OrgResourceParam;
import yonyou.bpm.rest.request.identity.TenantQueryParam;
import yonyou.bpm.rest.request.identity.TenantResourceParam;
import yonyou.bpm.rest.request.identity.UserGroupResourceParam;
import yonyou.bpm.rest.request.identity.UserLinkResourceParam;
import yonyou.bpm.rest.request.identity.UserResourceParam;
import yonyou.bpm.rest.request.repository.ProcessDefinitionModel;
import yonyou.bpm.rest.request.repository.ProcessDefinitionModelQuery;
import yonyou.bpm.rest.request.runtime.ProcessInstanceStartParam;
import yonyou.bpm.rest.request.task.TaskAttachmentResourceParam;
import yonyou.bpm.rest.request.task.TaskQueryParam;
import yonyou.bpm.rest.response.AttachmentResponse;
import yonyou.bpm.rest.response.CommentResponse;
import yonyou.bpm.rest.response.historic.HistoricProcessInstanceResponse;
import yonyou.bpm.rest.response.historic.HistoricTaskInstanceResponse;
import yonyou.bpm.rest.response.identity.TenantResponse;
import yonyou.bpm.rest.response.identity.UserResponse;
import yonyou.bpm.rest.response.repository.ProcessDefinitionResponse;
import yonyou.bpm.rest.response.runtime.task.RejectCheckResultRespnse;
import yonyou.bpm.rest.response.runtime.task.RejectInfoItemResponse;
import yonyou.bpm.rest.response.runtime.task.TaskResponse;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yonyou.crm.bpub.approval.util.ProcessQueryDateUtil;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.common.page.entity.Page;
import com.yonyou.crm.common.rest.constant.CrmCodeConstant;
import com.yonyou.crm.sys.role.constant.RoleTypeConstant;
import com.yonyou.crm.sys.role.entity.RoleVO;
import com.yonyou.crm.sys.role.service.RoleBizServiceImpl;

// 云审接口封装
@Service
public class YsService {
	
	private Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private JsonResultService jsonResultService;
    
    @Autowired
    private RoleBizServiceImpl roleService;

//	private String user = "13241003897";
//	
//	private String pwd = "nihao123";
    @Value("${bpmrest.user}")
    private String user;
    @Value("${bpmrest.pwd}")
    private String pwd;
	@Value("${bpmrest.server}")
	private String serverUrl;
	@Value("${bpmrest.tenant}")
    private String tenant ;
	@Value("${bpmrest.token}")
	private String token;
    /*
     * 返回开始数据的下标
     * @page 当前页码
     * @pageSize 每页显示条数
     * @return int
     */
    private int page2Start(int page, int pageSize) {
    	if (pageSize <= 0) {
    		pageSize = 10;
    	}
    	if (page <= 0) {
    		return 0;
    	}
    	return (page - 1) * pageSize;
    }
    
    private BpmRest bpmRestServices(String ysUserId, String ysTenantId) {
        
    	BaseParam baseParam=new BaseParam();

//		baseParam.setUserName(user);
//		baseParam.setPassWord(pwd);
    	if (ysUserId == null) {
    		baseParam.setOperatorID(user);
    	} else {
    		baseParam.setOperatorID(ysUserId);
    	}
        
        //1.U审rest服务地址：http://ys.yyuap.com/ubpm-web-rest
        baseParam.setServer(serverUrl);

        //2.==========rest安全调用=========begin
        //租户code
        //管理端租户管理节点生成的token
        baseParam.setTenant(tenant);
        baseParam.setClientToken(token);
        
//        String ysTenantId = "36d55410-cde3-11e7-9228-0242ac1e0286";
//        String ysTenantId= TenantLimit.getTenantLimit();
        //==========rest安全调用=========end
        //3.租户隔离，可为空，默认取rest安全多对应的戹
        if(ysTenantId!=null&&!"".equals(ysTenantId.trim())){
            baseParam.setTenantLimitId(ysTenantId);
        }
        
        return BpmRests.getBpmRest(baseParam);
    }
	
	/*
	 * 获取单点登录云审批设计器的url
	 */
	public String getUrlForLoginYs(String ysUserId, String ysTenantId, String userCode, String modelId) {
//		String userId = "6e67e1ac-d0e1-11e7-b424-0242ac1e1584";
		
//		String url = "https://ys.yonyoucloud.com/static/login.html?modelId=";
		String url = "static/login.html?modelId=";
		url += modelId + "&organizationId=" + ysTenantId + "&page=flow&usercode=" + userCode;
		url += "&userid="+ysUserId+"&token=" + token;
		return url;
	}
    
    /*
     * 创建租户(当前租户隔离为父租户)
     */
    public TenantResponse saveTenant(String name, String code, String address) throws RestException, CrmBusinessException {
       	TenantResourceParam param = new TenantResourceParam();
		param.setName(name);
		code = tenant + "_" + code;
		param.setCode(code);
		// TODO 租户管理员，应该取哪个值？
		param.setAdmin(user);
		param.setAddress(address);
		
		JsonNode jsonNode = (JsonNode)bpmRestServices(user, null).getIdentityService().saveTenant(param);
		if (jsonNode.get("errcode").asInt() != 0) {
			throw new CrmBusinessException(CrmCodeConstant.ServerError, jsonNode.get("errmsg").asText());
		}
		return jsonResultService.toObject(jsonNode.toString(), TenantResponse.class);
    }
    
    /*
     * 同步部门
     */
    public void synDepts(String ysTenantId, List<Map<String, Object>> deptList) throws RestException {
		int deptSize = deptList.size();
		
		// 转化为云审参数格式OrgResourceParam
		OrgResourceParam[] ysOrgParamArray = new OrgResourceParam[deptSize];
		int i = 0;
		for (Map<String, Object> deptMap : deptList) {
			OrgResourceParam ysOrgParam = new OrgResourceParam();
			// code,parentCode暂时先使用crm组织表中的id字段,后续再确定是否改成code
			String code = tenant + "_" + deptMap.get("id").toString();
			ysOrgParam.setCode(code);
			String name = deptMap.get("name") == null ? "" : (String)deptMap.get("name");
			ysOrgParam.setName(name);
			String parentCode = tenant + "_" + deptMap.get("fatherorg_id").toString();
			if (!code.equals(parentCode)) {
				ysOrgParam.setParentCode(parentCode);
			}
			
			String enableState = deptMap.get("enable_state") == null ? "" : deptMap.get("enable_state").toString();
			boolean enable = enableState.equals("1") ? true : false;
			ysOrgParam.setEnable(enable);
			// TODO 部门来源，是否需要设置
			// ysOrgParam.setSource("");
			ysOrgParam.setTenantId(ysTenantId);
			ysOrgParamArray[i] = ysOrgParam;
			i++;
		}
		// 调用云审saveOrgs接口，同步部门列表
		bpmRestServices(user, ysTenantId).getIdentityService().saveOrgs(ysOrgParamArray);
    }
    
    /*
	 * 同步角色(用户组)
	 */
	public void synUserGroups(String ysTenantId, List<RoleVO> roleVos) throws RestException {
		int roleSize = roleVos.size();
		UserGroupResourceParam[] userGroupResourceParamArray = new UserGroupResourceParam[roleSize];
		int i = 0;
		for (RoleVO roleVO : roleVos) {
			String name = roleVO.getName();
			String code = tenant + "_" + roleVO.getId().toString();
			if (name == null || name.isEmpty() || code == null || code.isEmpty()) {
				continue;
			}
			
			UserGroupResourceParam userGroupResourceParam = new UserGroupResourceParam();
			userGroupResourceParam.setCode(code);
			userGroupResourceParam.setName(name);
			userGroupResourceParam.setEnable(true);
			
			userGroupResourceParamArray[i] = userGroupResourceParam;
			i++;
		}
		// 调用云审saveUserGroups接口，同步用户组列表
		bpmRestServices(user, ysTenantId).getIdentityService().saveUserGroups(userGroupResourceParamArray);
	}
	
	/*
	 * 同步用户及用户角色(用户与用户组关联关系)
	 */
	public List<UserResponse> synUsers(String ysTenantId, List<Map<String, Object>> userList) throws RestException {
		int userSize = userList.size();
		
		// 转化为云审参数格式UserResourceParam
		UserResourceParam[] ysUserParamArray = new UserResourceParam[userSize];
		List<UserLinkResourceParam> userLinkResourceParamList = new ArrayList<UserLinkResourceParam>();
		int i = 0;
		for (Map<String, Object> userMap : userList) {
			String deptId = "";
			String orgCode = userMap.get("org_id").toString();
			if (userMap.get("dept_id") == null) {
				deptId = orgCode;
			} else {
				deptId = userMap.get("dept_id").toString();
				if (deptId.equals("0")) {
					deptId = orgCode;
				}
			}
			deptId = tenant + "_" + deptId;
			UserResourceParam ysUserParam = new UserResourceParam();
			String name = userMap.get("name") == null ? "" : (String)userMap.get("name");
			ysUserParam.setName(name);
			String email = userMap.get("email") == null ? "" : (String)userMap.get("email");
			ysUserParam.setMail(email);
			String phone = userMap.get("phone") == null ? "" : (String)userMap.get("phone");
			ysUserParam.setPhone(phone);
			
			
//			ysUserParam.setOrgCode(orgCode);
			ysUserParam.setDeptCode(deptId);
			String enableState = userMap.get("enable_state") == null ? "" : userMap.get("enable_state").toString();
			boolean enable = enableState.equals("1") ? true : false;
			ysUserParam.setEnable(enable);
			String code = userMap.get("id").toString();
			ysUserParam.setCode(tenant + "_" + code);
			List<RoleVO> userRoleList = roleService.getUserRole(Long.parseLong(code));
			if (userRoleList.size() > 0) {
				RoleVO userRole = userRoleList.get(0);
				int roleType = userRole.getType();
//				List<UserLinkResourceParam> links = new ArrayList<UserLinkResourceParam>();
			    UserLinkResourceParam link = new UserLinkResourceParam();
			    link.setUserCode(tenant + "_" + code);
				if (roleType == Integer.parseInt(RoleTypeConstant.SALESMANGER)) {
					link.setType(UserLinkResourceParam.TYPE_DEPT_MGR);
				} else {
					link.setType(UserLinkResourceParam.TYPE_DEPT);
				}
		/*	    link.setTargetCode(deptId);*/
//			    link.setTargetUserGroupCode(userRole.getId().toString());
			    userLinkResourceParamList.add(link);
//				ysUserParam.setLinks(links);
			}
			
			boolean isSysAdmin = false;
			ysUserParam.setSysadmin(isSysAdmin);
			// TODO 用户来源，是否需要设置
			ysUserParam.setSource("CRM");
			ysUserParam.setTenantId(ysTenantId);
			ysUserParamArray[i] = ysUserParam;
			i++;
		}
		
		// 调用云审saveUsers接口，同步用户列表
		List<UserResponse> responseSaveUsers = new ArrayList<UserResponse>();
		try {
			JsonNode jsonNode = (JsonNode)bpmRestServices(user, ysTenantId).getIdentityService().saveUsers(ysUserParamArray);
			responseSaveUsers = jsonResultService.jsonNode2List(jsonNode, UserResponse.class);
		} catch (RestException e) {
			e.printStackTrace();
			throw new CrmBusinessException(CrmCodeConstant.ServerError, "同步用户失败");
		}
		
		// 调用云审saveUserLinks接口，建立用户与用户组关联关系
		if (userLinkResourceParamList.size() > 0) {
			UserLinkResourceParam[] userLinkResourceParamArray = new UserLinkResourceParam[userLinkResourceParamList.size()];
			int m = 0;
			for (UserLinkResourceParam param : userLinkResourceParamList) {
				userLinkResourceParamArray[m] = param;
				m++;
			}
			try {
				bpmRestServices(user, ysTenantId).getIdentityService().saveUserLinks(userLinkResourceParamArray);
			} catch (RestException e) {
				e.printStackTrace();
				throw new CrmBusinessException(CrmCodeConstant.ServerError, "创建用户角色失败");
			}
		}
		return responseSaveUsers;
	}
    
    /*
     * 获取租户信息(当前租户隔离为父租户)
     */
    public TenantResponse getTenant(String code) throws RestException {
    	TenantQueryParam queryParam = new TenantQueryParam();
		queryParam.setCode(code);
		
		// 租户隔离为父租户
		TenantLimit.set("");
		JsonNode jsonNode = (JsonNode)bpmRestServices(user, null).getIdentityService().queryTenants(queryParam);
		if (jsonNode == null) {
			throw new CrmBusinessException(CrmCodeConstant.ServerError, "服务器异常，请联系管理员");
		}
		int total = jsonNode.get("total").asInt();
		if (total == 0) {
			return null;
		}
		JsonNode node = jsonNode.get("data").get(0);
		return jsonResultService.toObject(node.toString(), TenantResponse.class);
    }
    
    /*
	 * 设计流程模型,返回流程模型设计器url
	 */
    public ProcessDefinitionResponse createProcessDefinitionModel(String ysUserId, String ysTenantId, String processKey, String processName) throws RestException {
    	ProcessDefinitionModel processDefinitionModel = new ProcessDefinitionModel();
		processDefinitionModel.setKey(processKey);
		processDefinitionModel.setCategory("");
		processDefinitionModel.setName(processName);
		
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getRepositoryService().createProcessDefinitionModel(processDefinitionModel);
		return jsonResultService.toObject(jsonNode.toString(), ProcessDefinitionResponse.class);
	}
	
	/*
	 * 删除流程定义模型
	 */
	public boolean deleteProcessModel(String ysUserId, String ysTenantId, String modelId) throws RestException {
		return bpmRestServices(ysUserId, ysTenantId).getRepositoryService().deleteProcessDefinitionModel(modelId);
	}

	/**
	 * 根据流程定义、租户ID和业务key启动流程实例
	 *
	 * @param ysUserId
	 * @param processKey
	 * @param businessKey
	 * @return
	 * @throws RestException
	 */
	public HistoricProcessInstanceResponse startProcess(String ysUserId, String ysTenantId, String processKey, String businessKey, String instanceName, List<RestVariable> variables) throws RestException {
	    if (log.isDebugEnabled()) log.debug("启动流程。流程变量数据=" + jsonResultService.toJson(variables));
	    RuntimeService rt = bpmRestServices(ysUserId, ysTenantId).getRuntimeService();
	    ProcessInstanceStartParam param = new ProcessInstanceStartParam();
	    param.setProcessDefinitionKey(processKey);
	    param.setVariables(variables);
	    param.setBusinessKey(businessKey);
	    param.setProcessInstanceName(instanceName);
//	    param.setIsNext(true); // 是否第一个节点作为制单节点，直接指定到第二个节点
	    ObjectNode objectNode = (ObjectNode)rt.startProcess(param);
	    HistoricProcessInstanceResponse resp = jsonResultService.toObject(objectNode.toString(), HistoricProcessInstanceResponse.class);
	    return resp;
	}
	
	/*
	 * 删除流程定义模型(用于撤回)
	 */
	public boolean deleteProcessInstance(String ysUserId, String ysTenantId, String instanceId) throws RestException {
/*		return bpmRestServices(ysUserId, ysTenantId).getRuntimeService().deleteProcessInstanceWithAll(instanceId);*/
		return true;
	}

	/*
	 * 获取流程模型列表
	 */
	public Page<Map<String, Object>> getProcessDefinitionModels(String ysUserId, String ysTenantId, int page, int pageSize) throws RestException {
		// 初始化查询参数
		ProcessDefinitionModelQuery processDefinitionModelQuery = new ProcessDefinitionModelQuery();
		processDefinitionModelQuery.setOrder("desc");
		processDefinitionModelQuery.setSort("lastUpdateTime");
		processDefinitionModelQuery.setStart(page2Start(page, pageSize));
		processDefinitionModelQuery.setSize(pageSize);
		
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getRepositoryService().getProcessDefinitionModels(processDefinitionModelQuery);
		
		return jsonResultService.jsonNode2Page(jsonNode, page, pageSize);
	}
	
	/*
	 * 查询单个任务
	 */
	public Map<String, Object> getTask(String ysUserId, String ysTenantId, String taskId) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().getTask(taskId);
		
		return jsonResultService.jsonNode2Map(jsonNode);
	}
	
	/*
	 * 查询流程实例的所有任务列表
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> queryTasks(String ysUserId, String ysTenantId, String instanceId) throws RestException {
		TaskQueryParam queryParam = new TaskQueryParam();
		queryParam.setProcessInstanceId(instanceId);
		
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().queryTasks(queryParam);
		return (List<Map<String, Object>>)jsonResultService.jsonNode2Map(jsonNode).get("data");
	}

	/*
	 * 获取待办任务列表
	 */
	public Page<TaskResponse> queryTasksTodo(String ysUserId, String ysTenantId, 
			Map<String, Object> paraMap) throws RestException {
		TaskQueryParam taskQueryParam = new TaskQueryParam();
		int page = Integer.parseInt(paraMap.get("page").toString());
		int pageSize = Integer.parseInt(paraMap.get("pageSize").toString());
		int queryDateKey = 0;
		String keyword = null;
		if (paraMap.get("queryDateKey") != null) {
			queryDateKey = Integer.parseInt(paraMap.get("queryDateKey")
					.toString());
			List<Date> dates = ProcessQueryDateUtil.getDate(queryDateKey);
			if (dates != null) {
				taskQueryParam.setCreatedBefore(dates.get(1));
				taskQueryParam.setCreatedAfter(dates.get(0));
			}
		}
		if (paraMap.get("queryKey") != null) {
			keyword = (String) paraMap.get("queryKey");
			taskQueryParam.setProcessInstanceNameLike("%" + keyword.trim() + "%");
		}
		taskQueryParam.setAssignee(ysUserId);
		taskQueryParam.setReturnProcessInstance(true);
		taskQueryParam.setReturnTaskComment(true);
		taskQueryParam.setStart(page2Start(page, pageSize));
		taskQueryParam.setSize(pageSize);
		taskQueryParam.setOrder("desc");
		taskQueryParam.setSort("createTime");
		
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().queryTasksToDo(ysUserId, taskQueryParam);
		return jsonResultService.jsonNode2Page(jsonNode, page, pageSize, TaskResponse.class);
	}

	/**
	 * 根据用户id查询该用户的已办列表
	 *
	 * @throws RestException
	 */
	public Page<HistoricTaskInstanceResponse> queryTasksDone(String ysUserId, String ysTenantId, String taskDue, String taskToday, Integer priority,
			Map<String, Object> paraMap) throws RestException {
	    return queryTaskList(ysUserId, ysTenantId, taskDue, taskToday, priority,paraMap, true, true);
	}

	/**
	 * 根据用户id查询该用户的任务列表(历史任务)
	 *
	 * @param ysUserId
	 * @throws RestException
	 */
	public Page<HistoricTaskInstanceResponse> queryTaskList(String ysUserId, String ysTenantId, String taskDue, String taskToday, Integer priority,
			Map<String, Object> paraMap, Boolean isDone, Boolean returnHisProcessIns) throws RestException {
		        
		HistoricTaskQueryParam queryParam = new HistoricTaskQueryParam();
		int page = Integer.parseInt(paraMap.get("page").toString());
		int pageSize = Integer.parseInt(paraMap.get("pageSize").toString());
		int queryDateKey = 0;
		String keyword = null;
		if (paraMap.get("queryDateKey") != null) {
			queryDateKey = Integer.parseInt(paraMap.get("queryDateKey")
					.toString());
			List<Date> dates = ProcessQueryDateUtil.getDate(queryDateKey);
			if (dates != null) {
				queryParam.setTaskCreatedBefore(dates.get(1));
				queryParam.setTaskCreatedAfter(dates.get(0));
			}
		}
		if (paraMap.get("queryKey") != null) {
			keyword = (String) paraMap.get("queryKey");
			queryParam.setProcessInstanceNameLike("%" + keyword.trim() + "%");
		}
		queryParam.setTaskAssignee(ysUserId);
		queryParam.setIncludeProcessVariables(true);
		queryParam.setReturnParticipants(true);
		queryParam.setOrder("desc");
		queryParam.setSort("endTime");
		queryParam.setReturnHistoricProcessInstance(returnHisProcessIns);
		queryParam.setFinished(isDone);
		queryParam.setStart(page2Start(page, pageSize));
		queryParam.setSize(pageSize);
		
		if (taskDue != null && taskDue.length() > 0) {
			queryParam.setDueDateBefore(new Date());
	    }
	    if (taskToday != null && taskToday.length() > 0) {
	        Date today = new Date();
	        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	        String todayStr = sdf.format(today).substring(0, 10);
	        try {
	            Date today0 = sdf.parse(todayStr + " 00:00:00");
	            Date today1 = sdf.parse(todayStr + " 23:59:59");
	            queryParam.setTaskCreatedAfter(today0);
	            queryParam.setTaskCreatedBefore(today1);
	        } catch (ParseException e) {
	            log.error("时间解析错误", e);
	        }
	    }
	    if (priority != null) {
	    	queryParam.setTaskPriority(priority.toString());
	    }
	    if (keyword != null && keyword.trim().length() > 0) {
	    	queryParam.setTaskNameLike("%" + keyword + "%");
	    }
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getHistoryService().getHistoricTaskInstances(queryParam);
		return jsonResultService.jsonNode2Page(jsonNode, page, pageSize, HistoricTaskInstanceResponse.class);
	}
	
	/*
	 * 获取发起人发起的流程实例数量
	 */
	public int getHistoricProcessInstancesCount(String ysUserId, String ysTenantId, String keyword, Boolean isFinished) throws RestException {
		HistoricProcessInstancesQueryParam hpiqp = new HistoricProcessInstancesQueryParam();
	    hpiqp.setStartedBy(ysUserId);
	    if (isFinished != null) {
	    	hpiqp.setFinished(isFinished);
		}
	
	    if (keyword != null && keyword.trim().length() > 0) {
	        hpiqp.setProcessInstanceNameLike("%" + keyword + "%");
	    }
	
	    HistoryService hs = bpmRestServices(ysUserId, ysTenantId).getHistoryService();
	    JsonNode jsonNode = (JsonNode) hs.getHistoricProcessInstancesCount(hpiqp);
	    return jsonNode.get("instancesCount").asInt();
	}
	
	/*
	 * 获取任务数量
	 */
	public int getHistoricTasksCount(String ysUserId, String ysTenantId, String keyword, Boolean isFinished) throws RestException {
		HistoricTaskQueryParam queryParam = new HistoricTaskQueryParam();
		queryParam.setTaskAssignee(ysUserId);
		if (isFinished != null) {
			queryParam.setFinished(isFinished);
		}
		
	    if (keyword != null && keyword.trim().length() > 0) {
	    	queryParam.setTaskNameLike("%" + keyword + "%");
	    }
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getHistoryService().getHistoricTasksCount(queryParam);
		return jsonNode.get("tasksCount").asInt();
	}
	
	/*
	 * 获取某人发起的未完成流程实例
	 */
	public Page<HistoricProcessInstanceResponse> queryStartListNotFinished(String ysUserId, String ysTenantId, String keyword, int page, int pageSize)
	        throws RestException {
		return queryStartList(ysUserId, ysTenantId, keyword, page, pageSize, false);
	}
	
	/*
	 * 获取某人发起的已完成流程实例
	 */
	public Page<HistoricProcessInstanceResponse> queryStartListFinished(String ysUserId, String ysTenantId, String keyword, int page, int pageSize)
	        throws RestException {
		return queryStartList(ysUserId, ysTenantId, keyword, page, pageSize, true);
	}

	/**
	 * 查询某人发起的流程实例
	 * @param ysUserId
	 */
	public Page<HistoricProcessInstanceResponse> queryStartList(String ysUserId, String ysTenantId, String keyword, int page, int pageSize, Boolean isFinished)
	        throws RestException {
	    HistoricProcessInstancesQueryParam hpiqp = new HistoricProcessInstancesQueryParam();
	    hpiqp.setStartedBy(ysUserId);
	    hpiqp.setIncludeProcessVariables(true);
	    hpiqp.setStart(page2Start(page, pageSize));
	    hpiqp.setSize(pageSize);
	    if (isFinished != null) {
	    	hpiqp.setFinished(isFinished);
		}
	    String sortString = "startTime";
		if (isFinished != null && isFinished) {
			sortString = "endTime";
		}
		hpiqp.setOrder("desc");
		hpiqp.setSort(sortString);
	
	    if (keyword != null && keyword.trim().length() > 0) {
	        hpiqp.setProcessInstanceNameLike("%" + keyword + "%");
	    }
	
	    HistoryService hs = bpmRestServices(ysUserId, ysTenantId).getHistoryService();
	    JsonNode jsonNode = (JsonNode) hs.getHistoricProcessInstances(hpiqp);
	    return jsonResultService.jsonNode2Page(jsonNode, page, pageSize, HistoricProcessInstanceResponse.class);
	}

	/**
	 * 查询某人发起的流程实例
	 * 
	 * @param ysUserId
	 * @param ysTenantId
	 * @param paraMap
	 * @param isFinished
	 * @return
	 * @throws RestException
	 */
	public Page<HistoricProcessInstanceResponse> queryStartList(
			String ysUserId, String ysTenantId, Map<String, Object> paraMap,
			Boolean isFinished) throws RestException { 
		int page = Integer.parseInt(paraMap.get("page").toString());
		int pageSize = Integer.parseInt(paraMap.get("pageSize").toString());
		int queryDateKey = 0;
		String keyword = null;

		HistoricProcessInstancesQueryParam hpiqp = new HistoricProcessInstancesQueryParam();
		hpiqp.setStartedBy(ysUserId);
		hpiqp.setIncludeProcessVariables(true);
		hpiqp.setStart(page2Start(page, pageSize));
		hpiqp.setSize(pageSize);
		if (paraMap.get("queryDateKey") != null) {
			queryDateKey = Integer.parseInt(paraMap.get("queryDateKey")
					.toString());
			List<Date> dates = ProcessQueryDateUtil.getDate(queryDateKey);
			if (dates != null) {
				hpiqp.setStartedBefore(dates.get(1));
				hpiqp.setStartedAfter(dates.get(0));
			}
		}
		if (paraMap.get("queryKey") != null) {
			keyword = (String) paraMap.get("queryKey");
			hpiqp.setProcessInstanceNameLike("%" + keyword.trim() + "%");
		}
		if (isFinished != null) {
			hpiqp.setFinished(isFinished);
		}
		String sortString = "startTime";
		if (isFinished != null && isFinished) {
			sortString = "endTime";
		}
		hpiqp.setOrder("desc");
		hpiqp.setSort(sortString);

		HistoryService hs = bpmRestServices(ysUserId, ysTenantId)
				.getHistoryService();
		JsonNode jsonNode = (JsonNode) hs.getHistoricProcessInstances(hpiqp);
		return jsonResultService.jsonNode2Page(jsonNode, page, pageSize,
				HistoricProcessInstanceResponse.class);
	}
	/**
	 * 获得流程后续task(可用于查询流程待审人)
	 *
	 * @param instanceId
	 * @return
	 * @throws RestException
	 */
	public List<HistoricTaskInstanceResponse> queryInstanceNotFinishTaskAssigneeList(String ysUserId, String ysTenantId, String instanceId, String taskAssignee)
	        throws RestException {
		List<HistoricTaskInstanceResponse> rsList = new ArrayList<HistoricTaskInstanceResponse>();
		
	    HistoryService ht = bpmRestServices(ysUserId, ysTenantId).getHistoryService();// 历史服务
	    JsonNode obj = (JsonNode) ht.getHistoricProcessInstance(instanceId);
	    String endTime = obj.get("endTime").textValue(); 
	    if (endTime != null) {
	        // 说明该流程实例已结束
	        return rsList;
	    }
	
	    HistoricTaskQueryParam htp = new HistoricTaskQueryParam();
	    htp.setProcessInstanceId(instanceId);
	    htp.setFinished(false);// 只查询下一个未完成的task
	    htp.setReturnParticipants(true);// 返回参与人信息
	    htp.setReturnHistoricProcessInstance(true);
	    if (taskAssignee != null && !taskAssignee.isEmpty()) {
		    htp.setTaskAssignee(taskAssignee); // 设置任务拥有人
	    }
	    JsonNode jsonNode = (JsonNode) ht.getHistoricTaskInstances(htp);
	    return jsonResultService.jsonNode2List(jsonNode, HistoricTaskInstanceResponse.class);
	}

	/**
	 * 查询流程所有task列表(可用于查询审批历史)
	 *
	 * @param ysUserId
	 * @param instanceId
	 * @return
	 * @throws RestException
	 */
	public List<HistoricTaskInstanceResponse> queryInstanceAllHistoryTaskList(String ysUserId, String ysTenantId, String instanceId, String order, Boolean isFinished)
	        throws RestException {
	    HistoryService ht = bpmRestServices(ysUserId, ysTenantId).getHistoryService();// 历史服务
	    HistoricTaskQueryParam htp = new HistoricTaskQueryParam();
	    htp.setProcessInstanceId(instanceId);
	    htp.setIncludeProcessVariables(false);//不包含变量
	    htp.setReturnParticipants(true);
	    htp.setReturnHistoricProcessInstance(true);
	    htp.setReturnTaskComment(true);
	    if (isFinished != null) {
	    	htp.setFinished(isFinished);
	    }
	    htp.setOrder(order);
	    htp.setSort("endTime");
	    
	    JsonNode jsonNode = (JsonNode) ht.getHistoricTaskInstances(htp);
	    if (log.isDebugEnabled()) log.debug("queryInstanceAllHistoryTaskList==>" + jsonNode);
	    if (jsonNode == null) return null;
	    
	    return jsonResultService.jsonNode2List(jsonNode, HistoricTaskInstanceResponse.class);
	}
	
	/**
	 * 查询任务
	 *
	 * @param ysUserId
	 * @param taskId
	 * @return
	 * @throws RestException
	 */
	public HistoricTaskInstanceResponse queryTask(String ysUserId, String ysTenantId, String taskId)
	        throws RestException {
	    HistoryService ht = bpmRestServices(ysUserId, ysTenantId).getHistoryService();// 历史服务
	    HistoricTaskQueryParam htp = new HistoricTaskQueryParam();
	    htp.setTaskId(taskId);
//	    htp.setReturnParticipants(true);
//	    htp.setReturnHistoricProcessInstance(true);
	    htp.setReturnTaskComment(true);
	    
	    JsonNode jsonNode = (JsonNode) ht.getHistoricTaskInstances(htp);
	    if (log.isDebugEnabled()) log.debug("queryInstanceAllHistoryTaskList==>" + jsonNode);
	    if (jsonNode == null) return null;
	
	    List<HistoricTaskInstanceResponse> list = jsonResultService.jsonNode2List(jsonNode, HistoricTaskInstanceResponse.class);
	    if (list.size() == 0) {
	    	return null;
	    }
	    return list.get(0);
	}

	/**
	 * 提交某个任务的审批
	 *
	 * @param taskId
	 * @param agreed  是否同意申请
	 * @param comment 填写的审批意见
	 * @return 是否提交成功
	 * @throws RestException
	 */
	public boolean completeTask(String ysUserId, String ysTenantId, String taskId, boolean agreed, String comment)
	        throws RestException {
	    List<RestVariable> taskVariables = new ArrayList<RestVariable>();
	
	    RestVariable agreeVariable = new RestVariable();
	    agreeVariable.setName("agree");
	    agreeVariable.setValue(agreed ? "Y" : "N");
	    agreeVariable.setVariableScope(RestVariableScope.LOCAL);
	    taskVariables.add(agreeVariable);
	
	    TaskService ts = bpmRestServices(ysUserId, ysTenantId).getTaskService();
	    
	    if (comment == null || comment.trim().isEmpty()) {
	    	comment = "同意";
	    }
	    Object node = ts.completeWithComment(taskId, taskVariables, null, null, comment);
	    if (node != null) {
	        return true;
	    } else {
	        return false;
	    }
	}

	/**
	 * 根据流程实例ID获取审批评论信息(全部，不分页)
	 *
	 * @param processInstanceId
	 * @return
	 * @throws RestException
	 */
	public List<CommentResponse> queryComments(String ysUserId, String ysTenantId, String processInstanceId)
	        throws RestException {
	    HistoryService hs = bpmRestServices(ysUserId, ysTenantId).getHistoryService();
	    JsonNode jsonNode = (JsonNode) hs.getHistoricProcessInstancesComments(processInstanceId);
	    
	    return jsonResultService.jsonNode2List(jsonNode, CommentResponse.class);
	}

	/**
	 * 对一个任务进行评论
	 *
	 * @param userId
	 * @param taskId
	 * @param comment
	 * @param saveInstanceId
	 * @return
	 * @throws RestException
	 */
	public List<CommentResponse> commentTask(String ysUserId, String ysTenantId, String taskId, String comment, boolean saveInstanceId)
	        throws RestException {
	    TaskService ts = bpmRestServices(ysUserId, ysTenantId).getTaskService();
	    JsonNode jsonNode = (JsonNode) ts.addComment(taskId, comment, saveInstanceId);
	    if (log.isDebugEnabled()) log.debug("commentTask 返回:" + jsonNode);
	    return jsonResultService.jsonNode2List(jsonNode, CommentResponse.class);
	}
	
	/**
	 * 添加附件
	 * @param ysUserId
	 * @param taskId
	 * @param name
	 * @param desc
	 * @param is
	 * @return
	 * @throws RestException
	 */
	public AttachmentResponse createAttachment(String ysUserId, String ysTenantId, String taskId, String name, String desc, InputStream is)
	        throws RestException {	
	    TaskService ts = bpmRestServices(ysUserId, ysTenantId).getTaskService();
	    TaskAttachmentResourceParam parm = new TaskAttachmentResourceParam();
	    parm.setName(name);
	    parm.setDescription(desc);
	    parm.setValue(is);
	    JsonNode jsonNode = (JsonNode) ts.createAttachmentWithContent(taskId, parm);
	    if (log.isDebugEnabled()) {
	        log.debug("上传附件返回:" + jsonNode);
	    }
	
	    return jsonResultService.toObject(jsonNode.toString(), AttachmentResponse.class);
	}
	
	/**
	 * 查询附件
	 * @param ysUserId
	 * @param taskId
	 * @return
	 * @throws RestException
	 */
	public List<AttachmentResponse> queryAttachmentList(String ysUserId, String ysTenantId, String taskId)
	        throws RestException {
	    TaskService ts = bpmRestServices(ysUserId, ysTenantId).getTaskService();
	    JsonNode jsonNode = (JsonNode) ts.getAttachments(taskId);
	
	    if (log.isDebugEnabled()) {
	        log.debug("获取附件列表返回:" + jsonNode);
	    }
	
	   return jsonResultService.jsonNode2List(jsonNode, AttachmentResponse.class);
	}
	
	/**
	 * 获取附件内容
	 * @param userId
	 * @param taskId
	 * @param attachmentId
	 * @return
	 * @throws RestException
	 */
	public InputStream getAttachment(String ysUserId, String ysTenantId, String taskId, String attachmentId)
	        throws RestException {
	    TaskService ts = bpmRestServices(ysUserId, ysTenantId).getTaskService();
	    byte[] bytes = (byte[]) ts.getAttachmentContent(taskId, attachmentId);
	    return new ByteArrayInputStream(bytes);
	}

	/**
	 * 对实例添加comment
	 *
	 * @param userId
	 * @param instanceId
	 * @param comment
	 * @throws Exception
	 */
	public CommentResponse commentInstance(String ysUserId, String ysTenantId, String instanceId, String comment)
	        throws RestException {
	    HistoryService hs = bpmRestServices(ysUserId, ysTenantId).getHistoryService();
	    JsonNode jsonNode = (JsonNode) hs.addComment(instanceId, comment);
	    log.debug("HistoryService.addComment=" + jsonNode);
	    return jsonResultService.toObject(jsonNode.toString(), CommentResponse.class);
	}
	
	/**
	 * 查询流程实例全部信息
	 *
	 * @param ysUserId
	 * @param instanceId
	 * @throws RestException
	 */
	public HistoricProcessInstanceResponse getProcessInstanceAllInfo(String ysUserId, String ysTenantId, String instanceId) throws RestException {
		HistoryService ht = bpmRestServices(ysUserId, ysTenantId).getHistoryService();// 历史服务
	    
		BpmHistoricProcessInstanceParam param = new BpmHistoricProcessInstanceParam();
		
		HistoricProcessInstancesQueryParam hpiqp = new HistoricProcessInstancesQueryParam();
		hpiqp.setProcessInstanceId(instanceId);
		JsonNode jsonNode = (JsonNode) ht.getHistoricProcessInstance(instanceId, param);
		return jsonResultService.toObject(jsonNode.toString(), HistoricProcessInstanceResponse.class);
	}
	
	public boolean canWithDrawByInstance(String ysUserId, String ysTenantId, String instanceId) throws RestException {
		List<HistoricTaskInstanceResponse> notFinishedTaskList = queryInstanceNotFinishTaskAssigneeList(ysUserId, ysTenantId, instanceId, null);
		if (notFinishedTaskList.size() == 0) {
			return false;
		}
		
		boolean canWithdraw = true;
		for (HistoricTaskInstanceResponse resp : notFinishedTaskList) {
			String taskId = resp.getId();
			boolean canWithdrawTask = canWithDraw(ysUserId, ysTenantId, taskId);
			if (!canWithdrawTask) {
				canWithdraw = false;
				break;
			}
		}
		 
		return canWithdraw;
	}
	
	/*
	 * 判断任务是否可撤回
	 */
	public boolean canWithDraw(String ysUserId, String ysTenantId, String taskId) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().canWithDraw(taskId);
		boolean canWithdraw = jsonNode.get("canWithdraw").asBoolean();
		return canWithdraw;
	}
	
	/*
	 * 任务撤回
	 */
	public boolean withdrawTask(String ysUserId, String ysTenantId, String taskId) throws RestException {
		return bpmRestServices(ysUserId, ysTenantId).getTaskService().withdrawTask(taskId);
	}
	
	/*
	 * 驳回任务检查
	 */
	public Map<String, Object> rejectCheck1(String ysUserId, String ysTenantId, String taskId) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().rejectCheck(taskId);
		return jsonResultService.jsonNode2Map(jsonNode);
	}
	
	/*
	 * 驳回任务检查
	 */
	public RejectCheckResultRespnse rejectCheck(String ysUserId, String ysTenantId, String taskId) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getTaskService().rejectCheck(taskId);
		return jsonResultService.toObject(jsonResultService.toJson(jsonNode), RejectCheckResultRespnse.class);
	}
	
	/*
	 * 可驳回活动节点列表
	 */
	public RejectInfoItemResponse[] getRejectInfoItems(String ysUserId, String ysTenantId, String taskId) throws RestException {
		RejectCheckResultRespnse rejectCheckResultRespnse = rejectCheck(ysUserId, ysTenantId, taskId);
		if (rejectCheckResultRespnse.getRejectInfo() == null) {
			return null;
		}
		return rejectCheckResultRespnse.getRejectInfo().getAssignInfoItems();
	}
	
	
	
	/*
	 * 驳回到制单人
	 */
	public Map<String, Object> rejectToInitialActivity(String ysUserId, String ysTenantId, String instanceId, String rejectReason, String comment) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getRuntimeService().rejectToInitialActivity(instanceId, "rejectall", comment);
		return jsonResultService.jsonNode2Map(jsonNode);
	}
	
	/*
	 * 驳回到上一步(实际为驳回到上一个"可被驳回"的活动节点)
	 */
	public Map<String, Object> rejectToPreviousActivity(String ysUserId, String ysTenantId, String instanceId, String taskId, String comment) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getRuntimeService().rejectToPreviousActivity(instanceId, "reject", "reject", comment, taskId);
		return jsonResultService.jsonNode2Map(jsonNode);
	}
	
	/*
	 * 驳回到指定的活动节点
	 */
	public Map<String, Object> rejectToActivity(String ysUserId, String ysTenantId, String instanceId, String activityId, String comment) throws RestException {
		JsonNode jsonNode = (JsonNode)bpmRestServices(ysUserId, ysTenantId).getRuntimeService().rejectToActivity(instanceId, activityId, comment);
		return jsonResultService.jsonNode2Map(jsonNode);
	}

	public String getServerUrl() {
		return serverUrl;
	}

	public void setServerUrl(String serverUrl) {
		this.serverUrl = serverUrl;
	}

	public String getTenant() {
		return tenant;
	}

	public void setTenant(String tenant) {
		this.tenant = tenant;
	}

	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

}
